package com.ssy.lingxi.order.serviceimpl.base;

import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.OrderDO;
import com.ssy.lingxi.order.entity.OrderInnerHistoryDO;
import com.ssy.lingxi.order.entity.OrderOuterHistoryDO;
import com.ssy.lingxi.order.entity.OrderProductHistoryDO;
import com.ssy.lingxi.order.model.bo.OrderIdBO;
import com.ssy.lingxi.order.model.constant.*;
import com.ssy.lingxi.order.model.vo.basic.response.OrderInnerHistoryVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderOuterHistoryVO;
import com.ssy.lingxi.order.model.vo.common.request.OrderProductHistoryVO;
import com.ssy.lingxi.order.model.vo.common.response.OrderProductHistoryQueryVO;
import com.ssy.lingxi.order.repository.OrderInnerHistoryRepository;
import com.ssy.lingxi.order.repository.OrderOuterHistoryRepository;
import com.ssy.lingxi.order.repository.OrderProductHistoryRepository;
import com.ssy.lingxi.order.service.base.IBaseOrderHistoryService;
import com.ssy.lingxi.order.utils.NumberUtil;
import com.ssy.lingxi.order.utils.OrderStringUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 订单内、外流转记录相关接口
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-19
 */
@Service
public class BaseOrderHistoryServiceImpl implements IBaseOrderHistoryService {
    @Resource
    private OrderInnerHistoryRepository orderInnerHistoryRepository;

    @Resource
    private OrderOuterHistoryRepository orderOuterHistoryRepository;

    @Resource
    private OrderProductHistoryRepository orderProductHistoryRepository;

    /**
     * 保存订单内部流转记录
     * @param memberId 登录用户会员Id
     * @param roleId    登录用户会员角色Id
     * @param userName 登录用户姓名
     * @param organizationName 登录用户组织机构名称
     * @param jobTitle 登录用户职位
     * @param orderId 订单Id
     * @param orderNo 订单编号
     * @param operation  操作类型枚举
     * @param buyerInnerStatus 采购商内部状态
     * @param remark    备注
     */
    @Override
    public void saveBuyerInnerHistory(Long memberId, Long roleId, String userName, String organizationName, String jobTitle, Long orderId, String orderNo, OrderOperationEnum operation, Integer buyerInnerStatus, String remark) {
        saveOrderInnerHistory(memberId, roleId, userName, organizationName, jobTitle, Collections.singletonList(new OrderIdBO(orderId, orderNo)), OrderMemberTypeEnum.BUYER, operation, buyerInnerStatus, BuyerInnerStatusEnum.getNameByCode(buyerInnerStatus), remark);
    }

    /**
     * （批量）保存采购商订单内部流转记录
     *
     * @param memberId         登录用户会员Id
     * @param roleId           登录用户会员角色Id
     * @param userName         登录用户姓名
     * @param organizationName 登录用户组织机构名称
     * @param jobTitle         登录用户职位
     * @param orderIds         订单Id与编号列表
     * @param operation        操作类型枚举
     * @param buyerInnerStatus 采购商内部状态枚举值
     * @param remark           备注
     */
    @Override
    public void saveBuyerInnerHistory(Long memberId, Long roleId, String userName, String organizationName, String jobTitle, List<OrderIdBO> orderIds, OrderOperationEnum operation, Integer buyerInnerStatus, String remark) {
        saveOrderInnerHistory(memberId, roleId, userName, organizationName, jobTitle, orderIds, OrderMemberTypeEnum.BUYER, operation, buyerInnerStatus, BuyerInnerStatusEnum.getNameByCode(buyerInnerStatus), remark);
    }

    /**
     * 保存供应商订单内部流转记录
     *
     * @param memberId          登录用户会员Id
     * @param roleId            登录用户会员角色Id
     * @param userName          登录用户姓名
     * @param organizationName  登录用户组织机构名称
     * @param jobTitle          登录用户职位
     * @param orderId           订单Id
     * @param orderNo           订单编号
     * @param operation         操作类型枚举
     * @param vendorInnerStatus 供应商内部状态
     * @param remark            备注
     */
    @Override
    public void saveVendorInnerHistory(Long memberId, Long roleId, String userName, String organizationName, String jobTitle, Long orderId, String orderNo, OrderOperationEnum operation, Integer vendorInnerStatus, String remark) {
        saveOrderInnerHistory(memberId, roleId, userName, organizationName, jobTitle, Collections.singletonList(new OrderIdBO(orderId, orderNo)), OrderMemberTypeEnum.BUYER, operation, vendorInnerStatus, VendorInnerStatusEnum.getNameByCode(vendorInnerStatus), remark);
    }

    /**
     * （批量）保存订单内部流转记录
     *
     * @param memberId         登录用户会员Id
     * @param roleId           登录用户会员角色Id
     * @param userName         登录用户姓名
     * @param organizationName 登录用户组织机构名称
     * @param jobTitle         登录用户职位
     * @param orderIds         订单Id与编号列表
     * @param memberType       订单会员类型
     * @param operation        操作类型枚举
     * @param statusCode       供应商或采购商内部状态
     * @param statusName       供应商或采购商内部状态名称
     * @param remark           备注
     */
    @Async
    @Override
    public void saveOrderInnerHistory(Long memberId, Long roleId, String userName, String organizationName, String jobTitle, List<OrderIdBO> orderIds, OrderMemberTypeEnum memberType, OrderOperationEnum operation, Integer statusCode, String statusName, String remark) {
         List<OrderInnerHistoryDO> orderInnerHistories = orderIds.stream().map(order -> {
             OrderInnerHistoryDO orderInnerHistory = new OrderInnerHistoryDO();
             orderInnerHistory.setCreateTime(LocalDateTime.now());
             orderInnerHistory.setOrderId(order.getOrderId());
             orderInnerHistory.setOrderNo(order.getOrderNo());
             orderInnerHistory.setMemberId(memberId);
             orderInnerHistory.setRoleId(roleId);
             orderInnerHistory.setMemberType(memberType.getCode());
             orderInnerHistory.setOperator(userName);
             orderInnerHistory.setDepartment(organizationName);
             orderInnerHistory.setJobTitle(jobTitle);
             orderInnerHistory.setOperateCode(operation.getCode());
             orderInnerHistory.setOperation(operation.getName());
             orderInnerHistory.setStatusCode(statusCode);
             orderInnerHistory.setStatusName(statusName);
             orderInnerHistory.setRemark(StringUtils.hasLength(remark) ? remark.trim() : "");
             return orderInnerHistory;
         }).collect(Collectors.toList());
        orderInnerHistoryRepository.saveAll(orderInnerHistories);
    }

    /**
     * 查询采购订单内部流转记录
     *
     * @param order 订单
     * @return 内部流转记录
     */
    @Override
    public List<OrderInnerHistoryVO> listBuyerOrderInnerHistories(OrderDO order) {
        return listBuyerOrderInnerHistories(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getId());
    }

    /**
     * 查询采购订单内部流转记录
     *
     * @param buyerMemberId 采购会员Id
     * @param buyerRoleId   采购会员角色Id
     * @param orderId       订单Id
     * @return 内部流转记录
     */
    @Override
    public List<OrderInnerHistoryVO> listBuyerOrderInnerHistories(Long buyerMemberId, Long buyerRoleId, Long orderId) {
        return listOrderInnerHistories(buyerMemberId, buyerRoleId, orderId);
    }

    /**
     * 查询供应订单内部流转记录
     *
     * @param order 订单
     * @return 内部流转记录
     */
    @Override
    public List<OrderInnerHistoryVO> listVendorOrderInnerHistories(OrderDO order) {
        return listVendorOrderInnerHistories(order.getVendorMemberId(), order.getVendorRoleId(), order.getId());
    }

    /**
     * 查询供应订单内部流转记录
     *
     * @param vendorMemberId 供应会员Id
     * @param vendorRoleId   供应会员角色Id
     * @param orderId        订单Id
     * @return 内部流转记录
     */
    @Override
    public List<OrderInnerHistoryVO> listVendorOrderInnerHistories(Long vendorMemberId, Long vendorRoleId, Long orderId) {
        return listOrderInnerHistories(vendorMemberId, vendorRoleId, orderId);
    }

    /**
     * 查询订单内部流转记录
     *
     * @param memberId 采购会员或供应会员Id
     * @param roleId   采购会员或供应会员角色Id
     * @param orderId  订单Id
     * @return 内部流转记录
     */
    @Override
    public List<OrderInnerHistoryVO> listOrderInnerHistories(Long memberId, Long roleId, Long orderId) {
        return orderInnerHistoryRepository.findByMemberIdAndRoleIdAndOrderId(memberId, roleId, orderId, Sort.by("id").descending()).stream().map(historyDO -> {
            OrderInnerHistoryVO historyVO = new OrderInnerHistoryVO();
            historyVO.setId(historyDO.getId());
            historyVO.setCreateTime(historyDO.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            historyVO.setOperator(historyDO.getOperator());
            historyVO.setDepartment(historyDO.getDepartment());
            historyVO.setJobTitle(historyDO.getJobTitle());
            historyVO.setOperation(NumberUtil.isNullOrZero(historyDO.getOperateCode()) ? historyDO.getOperation() : OrderOperationEnum.getNameByCode(historyDO.getOperateCode()));
            historyVO.setStatusName((NumberUtil.isNullOrZero(historyDO.getMemberType()) || NumberUtil.isNullOrZero(historyDO.getStatusCode())) ? historyDO.getStatusName() : (historyDO.getMemberType().equals(OrderMemberTypeEnum.BUYER.getCode()) ? BuyerInnerStatusEnum.getNameByCode(historyDO.getOperateCode()) : VendorInnerStatusEnum.getNameByCode(historyDO.getOperateCode())));
            historyVO.setRemark(historyDO.getRemark());
            return historyVO;
        }).collect(Collectors.toList());
    }

    /**
     * 保存订单外部记录
     *
     * @param orderId            订单Id
     * @param buyerMemberId      采购会员Id
     * @param buyerRoleId        采购会员角色Id
     * @param operatorMemberName 操作会员名称
     * @param operatorRoleName   操作会员角色名称
     * @param operationEnum      操作方法枚举
     * @param outerStatus        订单外部状态
     * @param statusName         订单外部状态名称
     * @param remark             备注
     */
    @Async
    @Override
    public void saveBuyerOrderOuterHistory(Long orderId, String orderNo, Long buyerMemberId, Long buyerRoleId, String operatorMemberName, String operatorRoleName, OrderOperationEnum operationEnum, Integer outerStatus, String statusName, String remark) {
        OrderOuterHistoryDO historyDO = new OrderOuterHistoryDO();
        historyDO.setCreateTime(LocalDateTime.now());
        historyDO.setOrderId(orderId);
        historyDO.setOrderNo(orderNo);
        historyDO.setMemberId(buyerMemberId);
        historyDO.setRoleId(buyerRoleId);
        historyDO.setOperatorMemberName(operatorMemberName);
        historyDO.setOperatorRoleName(operatorRoleName);
        historyDO.setOperateCode(operationEnum.getCode());
        historyDO.setOperation(operationEnum.getName());
        historyDO.setOuterStatus(outerStatus);
        historyDO.setStatusName(statusName);
        historyDO.setRemark(StringUtils.hasLength(remark) ? remark.trim() : "");
        orderOuterHistoryRepository.saveAndFlush(historyDO);
    }

    /**
     * （批量）保存来自采购商的订单外部记录
     *
     * @param orderIds           订单Id与编号列表
     * @param buyerMemberId      采购会员Id
     * @param buyerRoleId        采购会员角色
     * @param operatorMemberName 指定的操作会员名称
     * @param operatorRoleName   指定的操作会员角色名称
     * @param operationEnum      操作方法枚举
     * @param outerStatus        订单外部状态
     * @param statusName         订单外部状态名称
     * @param remark             备注
     */
    @Override
    public void saveBuyerOrderOuterHistory(List<OrderIdBO> orderIds, Long buyerMemberId, Long buyerRoleId, String operatorMemberName, String operatorRoleName, OrderOperationEnum operationEnum, Integer outerStatus, String statusName, String remark) {
        orderOuterHistoryRepository.saveAll(orderIds.stream().map(order -> {
            OrderOuterHistoryDO historyDO = new OrderOuterHistoryDO();
            historyDO.setCreateTime(LocalDateTime.now());
            historyDO.setOrderId(order.getOrderId());
            historyDO.setOrderNo(order.getOrderNo());
            historyDO.setMemberId(buyerMemberId);
            historyDO.setRoleId(buyerRoleId);
            historyDO.setOperatorMemberName(operatorMemberName);
            historyDO.setOperatorRoleName(operatorRoleName);
            historyDO.setOperateCode(operationEnum.getCode());
            historyDO.setOperation(operationEnum.getName());
            historyDO.setOuterStatus(outerStatus);
            historyDO.setStatusName(statusName);
            historyDO.setRemark(StringUtils.hasLength(remark) ? remark.trim() : "");
            return historyDO;
        }).collect(Collectors.toList()));
    }

    /**
     * 保存来自供应商的订单外部记录
     *
     * @param orderId            订单Id
     * @param orderNo            订单编号
     * @param vendorMemberId     供应会员Id
     * @param vendorRoleId       供应会员角色Id
     * @param operatorMemberName 操作会员名称
     * @param operatorRoleName   操作会员角色名称
     * @param operationEnum      操作方法枚举
     * @param outerStatus        订单外部状态
     * @param statusName         订单外部状态名称
     * @param remark             备注
     */
    @Async
    @Override
    public void saveVendorOrderOuterHistory(Long orderId, String orderNo, Long vendorMemberId, Long vendorRoleId, String operatorMemberName, String operatorRoleName, OrderOperationEnum operationEnum, Integer outerStatus, String statusName, String remark) {
        OrderOuterHistoryDO historyDO = new OrderOuterHistoryDO();
        historyDO.setCreateTime(LocalDateTime.now());
        historyDO.setOrderId(orderId);
        historyDO.setOrderNo(orderNo);
        historyDO.setMemberId(vendorMemberId);
        historyDO.setRoleId(vendorRoleId);
        historyDO.setOperatorMemberName(operatorMemberName);
        historyDO.setOperatorRoleName(operatorRoleName);
        historyDO.setOperateCode(operationEnum.getCode());
        historyDO.setOperation(operationEnum.getName());
        historyDO.setOuterStatus(outerStatus);
        historyDO.setStatusName(statusName);
        historyDO.setRemark(StringUtils.hasLength(remark) ? remark.trim() : "");
        orderOuterHistoryRepository.saveAndFlush(historyDO);
    }

    /**
     * 查询订单外部流转记录
     *
     * @param order 订单
     * @return 外部流转记录
     */
    @Override
    public List<OrderOuterHistoryVO> listOrderOuterHistories(OrderDO order) {
        return listOrderOuterHistories(order.getId());
    }

    /**
     * 查询订单外部流转记录
     *
     * @param orderId       订单Id
     * @return 外部流转记录
     */
    @Override
    public List<OrderOuterHistoryVO> listOrderOuterHistories(Long orderId) {
        return orderOuterHistoryRepository.findByOrderId(orderId, Sort.by("id").descending()).stream().map(historyDO -> {
            OrderOuterHistoryVO historyVO = new OrderOuterHistoryVO();
            historyVO.setId(historyDO.getId());
            historyVO.setCreateTime(historyDO.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            historyVO.setOperatorRoleName(historyDO.getOperatorRoleName());
            historyVO.setOperation(NumberUtil.isNullOrZero(historyDO.getOperateCode()) ? historyDO.getOperation() : OrderOperationEnum.getNameByCode(historyDO.getOperateCode()));
            historyVO.setStatusName(NumberUtil.isNullOrZero(historyDO.getOuterStatus()) ? historyDO.getStatusName() : OrderOuterStatusEnum.getNameByCode(historyDO.getOuterStatus()));
            historyVO.setRemark(historyDO.getRemark());
            return historyVO;
        }).collect(Collectors.toList());
    }

    /**
     * 记录订单商品交易记录
     *
     * @param order 订单
     */
    @Async
    @Override
    public void saveOrderProductHistory(OrderDO order) {
        List<OrderProductHistoryDO> histories = order.getProducts().stream().distinct().map(orderProduct -> {
            OrderProductHistoryDO history = new OrderProductHistoryDO();
            history.setCreateTime(LocalDateTime.now());
            history.setOrderId(order.getId());
            history.setBuyerMemberId(order.getBuyerMemberId());
            history.setBuyerRoleId(order.getBuyerRoleId());
            history.setBuyerMemberName(order.getBuyerMemberName());
            history.setVendorMemberId(order.getVendorMemberId());
            history.setVendorRoleId(order.getVendorRoleId());
            history.setShopId(order.getShopId());
            history.setShopType(order.getShopType());
            history.setShopEnvironment(order.getShopEnvironment());
            history.setProductId(orderProduct.getProductId());
            history.setSkuId(orderProduct.getSkuId());
            history.setUnit(orderProduct.getUnit());
            history.setQuantity(orderProduct.getQuantity());
            return history;
        }).collect(Collectors.toList());
        orderProductHistoryRepository.saveAll(histories);
    }

    /**
     * 分页查询商品交易记录
     *
     * @param historyVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<OrderProductHistoryQueryVO>> pageOrderProductHistories(OrderProductHistoryVO historyVO) {
        Pageable pageable = PageRequest.of(historyVO.getCurrent() - 1, historyVO.getPageSize(), Sort.by("id").descending());
        Specification<OrderProductHistoryDO> specification = (Specification<OrderProductHistoryDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("shopId").as(Long.class), historyVO.getShopId()));
            list.add(criteriaBuilder.equal(root.get("productId").as(Long.class), historyVO.getProductId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<OrderProductHistoryDO> pageList = orderProductHistoryRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(history -> {
            OrderProductHistoryQueryVO queryVO = new OrderProductHistoryQueryVO();
            queryVO.setBuyerMemberName(OrderStringUtil.coverString(history.getBuyerMemberName()));
            queryVO.setQuantity(NumberUtil.formatToInteger(history.getQuantity()));
            queryVO.setCreateTime(history.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setUnit(history.getUnit());
            return queryVO;
        }).collect(Collectors.toList())));
    }
}
